package com.kexilo.core.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * Excel工具类 - 基于Hutool实现
 * 
 * @author Kexilo
 */
public class ExcelUtil<T> {
    
    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
    
    private final Class<T> clazz;
    
    public ExcelUtil(Class<T> clazz) {
        this.clazz = clazz;
    }
    
    /**
     * 导出Excel
     * 
     * @param list 数据列表
     * @param fileName 文件名
     * @param response HTTP响应
     */
    public void exportExcel(List<T> list, String fileName, HttpServletResponse response) {
        try {
            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", 
                    "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", StandardCharsets.UTF_8));
            
            // 创建ExcelWriter
            ExcelWriter writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);
            
            try {
                // 如果数据不为空，写入数据
                if (CollUtil.isNotEmpty(list)) {
                    // 获取字段信息并设置表头
                    List<Field> fields = getExportFields();
                    setHeader(writer, fields);
                    
                    // 写入数据
                    writeData(writer, list, fields);
                }
                
                // 设置列宽
                autoSizeColumns(writer);
                
                // 输出到响应流
                OutputStream outputStream = response.getOutputStream();
                writer.flush(outputStream, true);
                IoUtil.close(outputStream);
                
                log.info("Excel导出成功: fileName={}, recordCount={}", fileName, 
                        list != null ? list.size() : 0);
                
            } finally {
                writer.close();
            }
            
        } catch (Exception e) {
            log.error("Excel导出失败: fileName={}, error={}", fileName, e.getMessage(), e);
            throw new RuntimeException("Excel导出失败: " + e.getMessage());
        }
    }
    
    /**
     * 导入Excel
     * 
     * @param inputStream 输入流
     * @return 数据列表
     */
    public List<T> importExcel(InputStream inputStream) {
        List<T> resultList = new ArrayList<>();
        
        try {
            // 创建ExcelReader
            ExcelReader reader = cn.hutool.poi.excel.ExcelUtil.getReader(inputStream);
            
            // 获取总行数
            int rowCount = reader.getRowCount();
            if (rowCount <= 1) {
                log.warn("Excel文件无数据行");
                return resultList;
            }
            
            // 获取表头
            List<Object> headerList = reader.readRow(0);
            if (CollUtil.isEmpty(headerList)) {
                throw new RuntimeException("Excel文件格式错误：缺少表头");
            }
            
            // 获取字段映射
            Map<String, Integer> fieldColumnMap = getFieldColumnMap(headerList);
            
            // 读取数据行（从第二行开始）
            for (int i = 1; i < rowCount; i++) {
                List<Object> rowData = reader.readRow(i);
                if (CollUtil.isNotEmpty(rowData)) {
                    T obj = parseRowToObject(rowData, fieldColumnMap);
                    if (obj != null) {
                        resultList.add(obj);
                    }
                }
            }
            
            log.info("Excel导入成功: recordCount={}", resultList.size());
            
        } catch (Exception e) {
            log.error("Excel导入失败: error={}", e.getMessage(), e);
            throw new RuntimeException("Excel导入失败: " + e.getMessage());
        }
        
        return resultList;
    }
    
    /**
     * 获取需要导出的字段
     */
    private List<Field> getExportFields() {
        List<Field> fields = new ArrayList<>();
        Field[] allFields = clazz.getDeclaredFields();
        
        for (Field field : allFields) {
            if (shouldExport(field)) {
                field.setAccessible(true);
                fields.add(field);
            }
        }
        
        return fields;
    }
    
    /**
     * 判断字段是否应该导出
     */
    private boolean shouldExport(Field field) {
        // 排除static、final字段和特定字段
        if (java.lang.reflect.Modifier.isStatic(field.getModifiers()) ||
            java.lang.reflect.Modifier.isFinal(field.getModifiers()) ||
            "serialVersionUID".equals(field.getName())) {
            return false;
        }
        
        // 排除以下划线开头的私有字段
        return !field.getName().startsWith("_");
    }
    
    /**
     * 设置表头
     */
    private void setHeader(ExcelWriter writer, List<Field> fields) {
        for (int i = 0; i < fields.size(); i++) {
            Field field = fields.get(i);
            String columnName = getColumnName(field);
            writer.writeCellValue(i, 0, columnName);
        }
        
        // 设置表头样式
        writer.setHeaderAlias(createHeaderAlias(fields));
    }
    
    /**
     * 创建表头别名映射
     */
    private Map<String, String> createHeaderAlias(List<Field> fields) {
        Map<String, String> aliasMap = new LinkedHashMap<>();
        for (Field field : fields) {
            aliasMap.put(field.getName(), getColumnName(field));
        }
        return aliasMap;
    }
    
    /**
     * 获取列名
     */
    private String getColumnName(Field field) {
        // 可以添加注解支持，这里使用字段名转换
        return convertCamelCase(field.getName());
    }
    
    /**
     * 驼峰转换为可读格式
     */
    private String convertCamelCase(String fieldName) {
        if (StrUtil.isEmpty(fieldName)) {
            return fieldName;
        }
        
        StringBuilder result = new StringBuilder();
        
        for (int i = 0; i < fieldName.length(); i++) {
            char c = fieldName.charAt(i);
            if (Character.isUpperCase(c) && i > 0) {
                result.append(" ");
            }
            result.append(Character.toUpperCase(c));
        }
        
        return result.toString();
    }
    
    /**
     * 写入数据
     */
    private void writeData(ExcelWriter writer, List<T> list, List<Field> fields) {
        for (int i = 0; i < list.size(); i++) {
            T obj = list.get(i);
            for (int j = 0; j < fields.size(); j++) {
                Field field = fields.get(j);
                Object value = getFieldValue(obj, field);
                
                // 格式化值
                String formattedValue = formatValue(value);
                writer.writeCellValue(j, i + 1, formattedValue);
            }
        }
    }
    
    /**
     * 获取字段值
     */
    private Object getFieldValue(Object obj, Field field) {
        try {
            return ReflectUtil.getFieldValue(obj, field);
        } catch (Exception e) {
            log.warn("获取字段值失败: field={}, error={}", field.getName(), e.getMessage());
            return null;
        }
    }
    
    /**
     * 格式化值
     */
    private String formatValue(Object value) {
        if (value == null) {
            return "";
        }
        
        if (value instanceof LocalDateTime) {
            return ((LocalDateTime) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }
        
        return Convert.toStr(value, "");
    }
    
    /**
     * 自动调整列宽
     */
    private void autoSizeColumns(ExcelWriter writer) {
        try {
            // hutool会自动处理列宽，这里可以添加自定义逻辑
            writer.autoSizeColumnAll();
        } catch (Exception e) {
            log.warn("自动调整列宽失败: {}", e.getMessage());
        }
    }
    
    /**
     * 获取字段和列的映射关系
     */
    private Map<String, Integer> getFieldColumnMap(List<Object> headerList) {
        Map<String, Integer> fieldColumnMap = new HashMap<>();
        
        for (int i = 0; i < headerList.size(); i++) {
            Object header = headerList.get(i);
            if (header != null) {
                String columnName = header.toString().trim();
                String fieldName = getFieldNameByColumnName(columnName);
                if (StrUtil.isNotEmpty(fieldName)) {
                    fieldColumnMap.put(fieldName, i);
                }
            }
        }
        
        return fieldColumnMap;
    }
    
    /**
     * 根据列名获取字段名
     */
    private String getFieldNameByColumnName(String columnName) {
        Field[] fields = clazz.getDeclaredFields();
        
        for (Field field : fields) {
            if (getColumnName(field).equalsIgnoreCase(columnName)) {
                return field.getName();
            }
        }
        
        return null;
    }
    
    /**
     * 解析行数据为对象
     */
    private T parseRowToObject(List<Object> rowData, Map<String, Integer> fieldColumnMap) {
        try {
            T obj = ReflectUtil.newInstance(clazz);
            
            for (Map.Entry<String, Integer> entry : fieldColumnMap.entrySet()) {
                String fieldName = entry.getKey();
                Integer columnIndex = entry.getValue();
                
                if (columnIndex < rowData.size()) {
                    Object cellValue = rowData.get(columnIndex);
                    if (cellValue != null) {
                        Field field = ReflectUtil.getField(clazz, fieldName);
                        if (field != null) {
                            Object convertedValue = convertValue(cellValue, field.getType());
                            ReflectUtil.setFieldValue(obj, field, convertedValue);
                        }
                    }
                }
            }
            
            return obj;
            
        } catch (Exception e) {
            log.warn("解析行数据失败: error={}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 类型转换
     */
    private Object convertValue(Object value, Class<?> targetType) {
        if (value == null) {
            return null;
        }
        
        try {
            // 使用hutool的转换工具
            if (targetType == String.class) {
                return Convert.toStr(value);
            } else if (targetType == Integer.class || targetType == int.class) {
                return Convert.toInt(value);
            } else if (targetType == Long.class || targetType == long.class) {
                return Convert.toLong(value);
            } else if (targetType == Boolean.class || targetType == boolean.class) {
                return Convert.toBool(value);
            } else if (targetType == LocalDateTime.class) {
                String strValue = Convert.toStr(value);
                if (StrUtil.isNotEmpty(strValue)) {
                    try {
                        return LocalDateTime.parse(strValue, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    } catch (Exception e) {
                        // 尝试其他格式
                        return LocalDateTime.parse(strValue, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    }
                }
            }
            
            // 默认转换
            return Convert.convert(targetType, value);
            
        } catch (Exception e) {
            log.warn("类型转换失败: value={}, targetType={}, error={}", 
                    value, targetType.getSimpleName(), e.getMessage());
            return null;
        }
    }
}
